#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
股票趋势预测模块
根据新闻分析结果预测相关股票的趋势
"""

import os
import json
import yaml
import logging
import datetime
import pandas as pd
import numpy as np
from pathlib import Path
from collections import defaultdict
import tushare as ts
import akshare as ak
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

class TrendPredictor:
    """股票趋势预测类，负责根据新闻分析结果预测相关股票的趋势"""
    
    def __init__(self, config_path='config/config.yaml'):
        """
        初始化趋势预测器
        
        Args:
            config_path: 配置文件路径
        """
        self.config = self._load_config(config_path)
        self.prediction_config = self.config['prediction']
        self.stock_market_config = self.config['stock_market']
        self.storage_path = self.config['system']['data_storage']['stock_data_path']
        self.results_path = self.config['system']['data_storage']['results_path']
        
        # 确保存储目录存在
        Path(self.storage_path).mkdir(parents=True, exist_ok=True)
        Path(self.results_path).mkdir(parents=True, exist_ok=True)
        
        # 初始化股票数据API
        self._init_stock_api()
        
        # 初始化预测模型
        self.model = self._init_model()
        
        # 检查是否启用了大语言模型分析
        self.use_llm = self.config.get('llm_analysis', {}).get('enabled', False)
        self.llm_integration = self.config.get('llm_analysis', {}).get('integration', {})
        
        logger.info(f"趋势预测器初始化完成，LLM分析{'已启用' if self.use_llm else '未启用'}")
    
    def _load_config(self, config_path):
        """
        加载配置文件
        
        Args:
            config_path: 配置文件路径
            
        Returns:
            dict: 配置信息
        """
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
            logger.info(f"成功加载配置文件: {config_path}")
            return config
        except Exception as e:
            logger.error(f"加载配置文件失败: {e}")
            raise
    
    def _init_stock_api(self):
        """初始化股票数据API"""
        try:
            data_source = self.stock_market_config['data_source']
            
            if data_source == 'tushare':
                # 初始化Tushare
                api_token = self.stock_market_config['api_token']
                ts.set_token(api_token)
                self.stock_api = ts.pro_api()
                logger.info("成功初始化Tushare API")
            elif data_source == 'akshare':
                # 使用AKShare
                self.stock_api = ak
                logger.info("成功初始化AKShare API")
            else:
                logger.warning(f"未知的数据源: {data_source}，将使用AKShare作为默认数据源")
                self.stock_api = ak
        except Exception as e:
            logger.error(f"初始化股票数据API失败: {e}")
            # 使用AKShare作为备选
            self.stock_api = ak
    
    def _init_model(self):
        """
        初始化预测模型
        
        Returns:
            object: 预测模型
        """
        model_type = self.prediction_config['model']['type']
        algorithm = self.prediction_config['model']['algorithm']
        
        if model_type == 'ensemble':
            if algorithm == 'random_forest':
                model = RandomForestClassifier(
                    n_estimators=100,
                    max_depth=10,
                    random_state=42
                )
            elif algorithm == 'xgboost':
                try:
                    import xgboost as xgb
                    model = xgb.XGBClassifier(
                        n_estimators=100,
                        max_depth=5,
                        learning_rate=0.1,
                        random_state=42
                    )
                except ImportError:
                    logger.warning("XGBoost未安装，将使用RandomForest作为备选")
                    model = RandomForestClassifier(
                        n_estimators=100,
                        max_depth=10,
                        random_state=42
                    )
            else:
                logger.warning(f"未知的算法: {algorithm}，将使用RandomForest作为默认算法")
                model = RandomForestClassifier(
                    n_estimators=100,
                    max_depth=10,
                    random_state=42
                )
        else:
            logger.warning(f"未知的模型类型: {model_type}，将使用RandomForest作为默认模型")
            model = RandomForestClassifier(
                n_estimators=100,
                max_depth=10,
                random_state=42
            )
        
        logger.info(f"成功初始化预测模型: {type(model).__name__}")
        return model
    
    def load_processed_news(self, news_file):
        """
        加载处理后的新闻数据
        
        Args:
            news_file: 处理后的新闻数据文件路径
            
        Returns:
            list: 处理后的新闻列表
        """
        try:
            with open(news_file, 'r', encoding='utf-8') as f:
                processed_news = json.load(f)
            logger.info(f"成功加载 {len(processed_news)} 条处理后的新闻数据")
            return processed_news
        except Exception as e:
            logger.error(f"加载处理后的新闻数据失败: {e}")
            return []
    
    def extract_stock_info(self, processed_news):
        """
        从处理后的新闻中提取股票信息
        
        Args:
            processed_news: 处理后的新闻列表
            
        Returns:
            dict: 股票信息，格式为 {stock_code: {'news': [], 'sentiment': [], 'count': 0}}
        """
        stock_info = defaultdict(lambda: {'news': [], 'sentiment': [], 'count': 0})
        
        for news in processed_news:
            try:
                # 获取新闻中提到的股票
                entities = news['processed']['entities']
                stocks = entities.get('stocks', [])
                
                # 检查原始新闻数据中是否有related_stocks字段
                if 'original' in news and 'related_stocks' in news['original']:
                    related_stocks = news['original']['related_stocks']
                    if related_stocks and isinstance(related_stocks, list):
                        # 添加到stocks列表
                        stocks.extend(related_stocks)
                        # 去重
                        stocks = list(set(stocks))
                
                # 获取新闻情感
                sentiment = news['processed']['sentiment']
                
                # 更新股票信息
                for stock in stocks:
                    stock_info[stock]['news'].append(news)
                    stock_info[stock]['sentiment'].append(sentiment)
                    stock_info[stock]['count'] += 1
            
            except Exception as e:
                logger.error(f"提取股票信息失败: {e}")
                continue
        
        logger.info(f"从新闻中提取到 {len(stock_info)} 只股票的信息")
        return stock_info
    
    def get_stock_data(self, stock_code, days=30):
        """
        获取股票历史数据
        
        Args:
            stock_code: 股票代码
            days: 获取的天数
            
        Returns:
            DataFrame: 股票历史数据
        """
        try:
            # 解析股票代码
            code = stock_code.split('.')[0]
            market = stock_code.split('.')[1]
            
            # 确定开始和结束日期
            end_date = datetime.datetime.now().strftime('%Y%m%d')
            start_date = (datetime.datetime.now() - datetime.timedelta(days=days)).strftime('%Y%m%d')
            
            # 根据数据源获取数据
            if hasattr(self, 'stock_api') and self.stock_market_config['data_source'] == 'tushare':
                # 使用Tushare获取数据
                df = self.stock_api.daily(ts_code=stock_code, start_date=start_date, end_date=end_date)
                
                # 重命名列
                df = df.rename(columns={
                    'trade_date': 'date',
                    'open': 'open',
                    'high': 'high',
                    'low': 'low',
                    'close': 'close',
                    'vol': 'volume',
                    'amount': 'amount'
                })
                
            else:
                # 使用AKShare获取数据
                if market == 'SH':
                    market_code = 'sh' + code
                elif market == 'SZ':
                    market_code = 'sz' + code
                else:
                    market_code = code
                
                df = ak.stock_zh_a_hist(symbol=market_code, period="daily", start_date=start_date, end_date=end_date)
                
                # 重命名列
                df = df.rename(columns={
                    '日期': 'date',
                    '开盘': 'open',
                    '最高': 'high',
                    '最低': 'low',
                    '收盘': 'close',
                    '成交量': 'volume',
                    '成交额': 'amount'
                })
            
            # 确保日期格式一致
            df['date'] = pd.to_datetime(df['date'])
            
            # 按日期排序
            df = df.sort_values('date')
            
            logger.info(f"成功获取股票 {stock_code} 的历史数据，共 {len(df)} 条记录")
            return df
        
        except Exception as e:
            logger.error(f"获取股票 {stock_code} 的历史数据失败: {e}")
            return pd.DataFrame()
    
    def calculate_features(self, stock_data, stock_info):
        """
        计算用于预测的特征
        
        Args:
            stock_data: 股票历史数据
            stock_info: 从新闻中提取的股票信息
            
        Returns:
            pd.DataFrame: 特征数据
        """
        try:
            if stock_data.empty:
                logger.warning("股票数据为空，无法计算特征")
                return pd.DataFrame()
            
            # 复制数据防止修改原始数据
            df = stock_data.copy()
            
            # 将日期设置为索引
            if 'date' in df.columns:
                df['date'] = pd.to_datetime(df['date'])
                df = df.set_index('date')
            
            # 获取预测天数
            n = self.prediction_config['settings']['prediction_horizon'][0]
            
            # 计算未来n天的收盘价
            df['future_close'] = df['close'].shift(-n)
            
            # 计算技术指标
            # 根据数据量动态调整窗口大小
            data_length = len(df)
            max_window = min(20, data_length - 2)  # 确保窗口不超过数据长度减2
            
            if max_window >= 5:
                df['ma5'] = df['close'].rolling(window=5, min_periods=2).mean()
            else:
                df['ma5'] = df['close']
                
            if max_window >= 10:
                df['ma10'] = df['close'].rolling(window=10, min_periods=4).mean()
            else:
                df['ma10'] = df['close']
                
            if max_window >= 20:
                df['ma20'] = df['close'].rolling(window=20, min_periods=8).mean()
            else:
                df['ma20'] = df['close']
            
            # 计算其他技术指标
            # RSI指标
            delta = df['close'].diff()
            gain = delta.where(delta > 0, 0)
            loss = -delta.where(delta < 0, 0)
            
            avg_gain = gain.rolling(window=min(14, max_window), min_periods=1).mean()
            avg_loss = loss.rolling(window=min(14, max_window), min_periods=1).mean()
            
            rs = avg_gain / avg_loss.replace(0, 0.001)  # 避免除以0
            df['rsi'] = 100 - (100 / (1 + rs))
            
            # Calculate MACD
            fast_span = min(12, max_window)
            slow_span = min(26, max_window)
            signal_span = min(9, max_window)
            df['ema12'] = df['close'].ewm(span=fast_span, adjust=False, min_periods=1).mean()
            df['ema26'] = df['close'].ewm(span=slow_span, adjust=False, min_periods=1).mean()
            df['macd'] = df['ema12'] - df['ema26']
            df['signal'] = df['macd'].ewm(span=signal_span, adjust=False, min_periods=1).mean()
            df['macd_hist'] = df['macd'] - df['signal']
            
            # Calculate Bollinger Bands
            window = min(20, max_window)
            df['ma'] = df['close'].rolling(window=window, min_periods=1).mean()
            df['std'] = df['close'].rolling(window=window, min_periods=1).std()
            df['upper_band'] = df['ma'] + 2 * df['std']
            df['lower_band'] = df['ma'] - 2 * df['std']
            
            # Calculate price change percentage
            df['pct_change'] = df['close'].pct_change()
            
            # Calculate volatility
            df['volatility'] = df['close'].pct_change().rolling(window=min(10, max_window), min_periods=1).std()
            
            # 计算成交量变化
            df['volume_change'] = df['volume'].pct_change()
            
            # 计算价格动量
            df['momentum'] = df['close'].pct_change(periods=min(5, max_window))
            
            # 计算未来涨跌幅
            df['future_pct_change'] = (df['future_close'] - df['close']) / df['close'] * 100
            
            # 根据未来涨跌幅确定标签
            df['label'] = np.where(df['future_pct_change'] > 1, 1, np.where(df['future_pct_change'] < -1, -1, 0))
            
            # 添加新闻情感特征
            # 获取最新日期
            latest_date = df.index.max()
            
            # 计算新闻情感得分
            sentiment_scores = [s['score'] for s in stock_info['sentiment']]
            avg_sentiment = np.mean(sentiment_scores) if sentiment_scores else 0.5
            
            # 计算新闻数量
            news_count = stock_info['count']
            
            # 为最新日期添加新闻特征
            df.loc[df.index == latest_date, 'sentiment_score'] = avg_sentiment
            df.loc[df.index == latest_date, 'news_count'] = news_count
            
            # 填充缺失值
            df = df.fillna(method='ffill').fillna(method='bfill')  # 前向和后向填充
            df = df.dropna(subset=['future_pct_change', 'label'])  # 只删除未来价格和标签缺失的行
            
            logger.info(f"成功计算特征，共 {len(df)} 条记录")
            return df
        
        except Exception as e:
            logger.error(f"计算特征失败: {e}")
            return pd.DataFrame()
    
    def train_model(self, features_df):
        """
        训练预测模型
        
        Args:
            features_df: 特征数据
            
        Returns:
            bool: 训练是否成功
        """
        if features_df.empty or len(features_df) < 10:
            logger.warning("特征数据不足，无法训练模型")
            return False
        
        try:
            # 准备训练数据
            feature_columns = [
                'open', 'high', 'low', 'close', 'volume',
                'ma5', 'ma10', 'ma20', 'rsi', 'macd', 'macd_hist',
                'upper_band', 'lower_band', 'pct_change',
                'sentiment_score', 'news_count'
            ]
            
            X = features_df[feature_columns].values
            y = features_df['label'].values
            
            # 划分训练集和测试集
            X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
            
            # 训练模型
            self.model.fit(X_train, y_train)
            
            # 评估模型
            y_pred = self.model.predict(X_test)
            accuracy = accuracy_score(y_test, y_pred)
            
            logger.info(f"模型训练完成，测试集准确率: {accuracy:.4f}")
            
            # 特征重要性
            if hasattr(self.model, 'feature_importances_'):
                importances = self.model.feature_importances_
                feature_importance = pd.DataFrame({
                    'feature': feature_columns,
                    'importance': importances
                }).sort_values('importance', ascending=False)
                
                logger.info(f"特征重要性排名前5: {feature_importance.head(5).to_dict()}")
            
            return True
        
        except Exception as e:
            logger.error(f"训练模型失败: {e}")
            return False
    
    def predict_trend(self, features_df):
        """
        预测股票趋势
        
        Args:
            features_df: 特征数据
            
        Returns:
            dict: 预测结果
        """
        if features_df.empty:
            logger.warning("特征数据为空，无法进行预测")
            return {'trend': 'unknown', 'confidence': 0, 'details': {}}
        
        try:
            # 准备预测数据
            feature_columns = [
                'open', 'high', 'low', 'close', 'volume',
                'ma5', 'ma10', 'ma20', 'rsi', 'macd', 'macd_hist',
                'upper_band', 'lower_band', 'pct_change',
                'sentiment_score', 'news_count'
            ]
            
            # 获取最新一条数据
            latest_data = features_df.iloc[-1]
            X = latest_data[feature_columns].values.reshape(1, -1)
            
            # 检查模型是否已训练
            if not hasattr(self.model, 'classes_'):
                logger.warning("模型尚未训练，无法进行预测")
                # 返回中性结果
                return {
                    'trend': 'neutral',
                    'confidence': 0.5,
                    'prediction': 'stable',  # 添加预测结果
                    'details': {
                        'technical_score': 0,
                        'sentiment_score': latest_data.get('sentiment_score', 0),
                        'news_count': latest_data.get('news_count', 0),
                        'price': latest_data.get('close', 0),
                        'volume': latest_data.get('volume', 0),
                        'date': str(latest_data.name) if hasattr(latest_data, 'name') else ''
                    }
                }
            
            # 预测
            prediction = self.model.predict(X)[0]
            
            # 获取预测概率
            probabilities = self.model.predict_proba(X)[0]
            confidence = max(probabilities)
            
            # 确定趋势
            if prediction == 1:
                trend = 'up'
            elif prediction == -1:
                trend = 'down'
            else:
                trend = 'stable'
            
            # 构建预测结果
            result = {
                'trend': trend,
                'confidence': float(confidence),
                'details': {
                    'date': latest_data['date'].strftime('%Y-%m-%d'),
                    'close': float(latest_data['close']),
                    'ma5': float(latest_data['ma5']),
                    'ma10': float(latest_data['ma10']),
                    'rsi': float(latest_data['rsi']),
                    'macd': float(latest_data['macd']),
                    'sentiment_score': float(latest_data['sentiment_score']),
                    'news_count': int(latest_data['news_count']),
                    'prediction_horizon': self.prediction_config['settings']['prediction_horizon'][0]
                }
            }
            
            logger.info(f"预测结果: 趋势={trend}, 置信度={confidence:.4f}")
            return result
        
        except Exception as e:
            logger.error(f"预测趋势失败: {e}")
            return {'trend': 'unknown', 'confidence': 0, 'details': {}}
    
    def _calculate_news_sentiment(self, stock_code):
        """根据股票代码计算新闻情感得分"""
        return 0, 0  # 默认情况下返回0得分和0新闻数量
    
    def get_company_name(self, stock_code):
        """
        获取股票对应的公司名称
        
        Args:
            stock_code: 股票代码
            
        Returns:
            str: 公司名称
        """
        # 简单实现，实际应用中应该从数据库或API获取公司名称
        try:
            # 尝试从tushare获取公司名称
            if self.stock_api and stock_code.endswith(('.SH', '.SZ')):
                df = self.stock_api.query('stock_basic', exchange='', 
                                       fields='ts_code,name',
                                       ts_code=stock_code)
                if not df.empty:
                    return df.iloc[0]['name']
            
            # 如果无法获取，返回股票代码作为公司名称
            return f"Company {stock_code}"
        except Exception as e:
            logger.warning(f"获取公司名称失败: {e}")
            return f"Company {stock_code}"
    
    def get_industry(self, stock_code):
        """
        获取股票对应的行业分类
        
        Args:
            stock_code: 股票代码
            
        Returns:
            str: 行业分类
        """
        # 简单实现，实际应用中应该从数据库或API获取行业信息
        try:
            # 尝试从tushare获取行业信息
            if self.stock_api and stock_code.endswith(('.SH', '.SZ')):
                df = self.stock_api.query('stock_basic', exchange='', 
                                       fields='ts_code,industry',
                                       ts_code=stock_code)
                if not df.empty and 'industry' in df.columns:
                    return df.iloc[0]['industry']
            
            # 如果无法获取，返回默认行业
            return "未知行业"
        except Exception as e:
            logger.warning(f"获取行业信息失败: {e}")
            return "未知行业"
    
    def extract_keywords(self, news_list):
        """
        从新闻列表中提取关键词
        
        Args:
            news_list: 包含新闻的列表
            
        Returns:
            list: 关键词列表
        """
        try:
            # 提取所有新闻的关键词
            all_keywords = []
            for news in news_list:
                if 'processed' in news and 'keywords' in news['processed']:
                    keywords = news['processed']['keywords']
                    # 每条新闻取前5个关键词
                    top_keywords = keywords[:5] if len(keywords) > 5 else keywords
                    all_keywords.extend([kw[0] for kw in top_keywords])
            
            # 去重并返回前10个关键词
            unique_keywords = list(set(all_keywords))
            return unique_keywords[:10] if len(unique_keywords) > 10 else unique_keywords
        
        except Exception as e:
            logger.error(f"提取关键词失败: {e}")
            return []
    
    def analyze_stock(self, stock_code, stock_info, llm_analysis=None):
        """
        Analyze a stock based on technical analysis and optional LLM analysis.
        
        Args:
            stock_code (str): The code of the stock to analyze
            stock_info (dict): Additional information about the stock
            llm_analysis (dict, optional): Analysis from LLM if available
            
        Returns:
            dict: Analysis results including prediction and confidence
        """
        try:
            # Get historical data
            historical_data = self.get_stock_data(stock_code)
            if historical_data is None or historical_data.empty:
                logger.warning(f"No historical data for {stock_code}")
                return {}
                
            # Calculate features
            features = self.calculate_features(historical_data, stock_info)
            
            # Predict trend
            prediction = self.predict_trend(features)
            
            # Get company info
            company_name = self.get_company_name(stock_code)
            industry = self.get_industry(stock_code)
            
            # Calculate sentiment
            news_sentiment = 0.5
            if stock_info and 'sentiment' in stock_info:
                news_sentiment = np.mean([item['score'] for item in stock_info['sentiment']])
                
            # Ensure prediction is returned as a dictionary with confidence
            if isinstance(prediction, str):
                # Convert string prediction to dictionary format
                trend_value = prediction
                prediction = {
                    'prediction': trend_value,
                    'confidence': 0.6,  # Default confidence value
                    'details': {}
                }
            elif isinstance(prediction, dict) and 'prediction' not in prediction:
                # If prediction is a dict but missing the 'prediction' key
                if 'trend' in prediction:
                    prediction['prediction'] = prediction['trend']
                    
                # Ensure there's a confidence value
                if 'confidence' not in prediction:
                    prediction['confidence'] = 0.6
                    
                # Ensure there's a details dictionary
                if 'details' not in prediction:
                    prediction['details'] = {}
                    
            # Include additional information
            result = {
                'stock_code': stock_code,
                'company_name': company_name,
                'industry': industry,
                'prediction': prediction,
                'news_sentiment': news_sentiment,
                'latest_price': float(historical_data['close'].iloc[-1]) if not historical_data.empty else 0.0,
                'price_change': float(historical_data['pct_change'].iloc[-1]) if not historical_data.empty and 'pct_change' in historical_data.columns else 0.0,
            }
            
            return result
            
        except Exception as e:
            logger.error(f"分析股票 {stock_code} 失败: {e}")
            return {}
    
    def analyze_all_stocks(self, processed_news, llm_analysis=None):
        """
        分析所有股票
        
        Args:
            processed_news: 处理后的新闻列表
            llm_analysis: 大语言模型分析结果（可选）
            
        Returns:
            dict: 所有股票的分析结果
        """
        try:
            # 提取股票信息
            stock_info = self.extract_stock_info(processed_news)
            
            # 分析结果
            analysis_results = {}
            
            # 遍历所有股票
            for stock_code, info in stock_info.items():
                # 只分析提及次数大于阈值的股票
                min_count = self.prediction_config.get('min_news_count', 1)
                if info['count'] >= min_count:
                    # 分析股票
                    result = self.analyze_stock(stock_code, info, llm_analysis)
                    
                    if result:
                        analysis_results[stock_code] = result
            
            # 如果启用了LLM但没有传入分析结果，检查是否有其他推荐的股票
            if self.use_llm and llm_analysis and self.llm_integration.get('use_in_strategy', True):
                portfolio_recommendations = llm_analysis.get('stock_analysis', {}).get('portfolio_recommendations', [])
                for rec in portfolio_recommendations:
                    stock_code = rec.get('stock_code', '')
                    if stock_code and stock_code not in analysis_results:
                        # 为LLM推荐但未在新闻中提及的股票创建分析结果
                        stock_analyses = llm_analysis.get('stock_analysis', {}).get('stock_analysis', {})
                        if stock_code in stock_analyses:
                            llm_result = stock_analyses[stock_code]
                            company_name = self.get_company_name(stock_code)
                            industry = self.get_industry(stock_code)
                            
                            # 根据评级确定预测
                            rating = llm_result.get('rating', '')
                            if rating in ['强买入', '买入']:
                                llm_prediction = '上涨'
                                llm_confidence = 0.85 if rating == '强买入' else 0.75
                            elif rating in ['强卖出', '卖出']:
                                llm_prediction = '下跌'
                                llm_confidence = 0.85 if rating == '强卖出' else 0.75
                            else:  # 持有
                                llm_prediction = '稳定'
                                llm_confidence = 0.65
                            
                            analysis_results[stock_code] = {
                                'name': company_name,
                                'industry': industry,
                                'prediction': llm_prediction,
                                'confidence': round(float(llm_confidence), 2),
                                'sentiment_score': 0.6,  # 默认值
                                'related_news': [],
                                'keywords': [],
                                'llm_analysis': llm_result.get('analysis', ''),
                                'llm_prediction': llm_prediction,
                                'llm_confidence': round(float(llm_confidence), 2),
                                'llm_recommendation': True  # 标记为LLM推荐
                            }
            
            logger.info(f"成功分析 {len(analysis_results)} 只股票")
            return analysis_results
            
        except Exception as e:
            logger.error(f"分析所有股票失败: {e}")
            return {}
    
    def save_analysis_results(self, analysis_results):
        """
        保存分析结果
        
        Args:
            analysis_results: 分析结果列表
            
        Returns:
            str: 保存的文件路径
        """
        if not analysis_results:
            logger.warning("没有分析结果需要保存")
            return None
        
        try:
            # 生成文件名
            timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"stock_analysis_{timestamp}.json"
            filepath = os.path.join(self.results_path, filename)
            
            # 保存为JSON文件
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(analysis_results, f, ensure_ascii=False, indent=2)
            
            logger.info(f"成功保存 {len(analysis_results)} 条分析结果到 {filepath}")
            return filepath
        
        except Exception as e:
            logger.error(f"保存分析结果失败: {e}")
            return None

def main():
    """主函数"""
    import sys
    
    try:
        # 检查命令行参数
        if len(sys.argv) < 2:
            print("用法: python trend_predictor.py <processed_news_file_path> [llm_analysis_file_path]")
            return
        
        news_file = sys.argv[1]
        llm_analysis_file = sys.argv[2] if len(sys.argv) > 2 else None
        
        # 创建预测器
        predictor = TrendPredictor()
        
        # 加载处理后的新闻
        processed_news = predictor.load_processed_news(news_file)
        
        if not processed_news:
            print("没有找到处理后的新闻数据或数据为空")
            return
        
        # 加载LLM分析结果（如果有）
        llm_analysis = None
        if llm_analysis_file and os.path.exists(llm_analysis_file):
            try:
                with open(llm_analysis_file, 'r', encoding='utf-8') as f:
                    llm_analysis = json.load(f)
                print(f"成功加载LLM分析结果: {llm_analysis_file}")
            except Exception as e:
                print(f"加载LLM分析结果失败: {e}")
        
        # 分析所有股票
        analysis_results = predictor.analyze_all_stocks(processed_news, llm_analysis)
        
        # 保存分析结果
        saved_path = predictor.save_analysis_results(analysis_results)
        
        print(f"成功分析并保存了 {len(analysis_results)} 只股票的分析结果到 {saved_path}")
        
    except Exception as e:
        logger.error(f"趋势预测失败: {e}")

if __name__ == "__main__":
    main() 